#pragma once

// #ifdef MYTHREAD

#include <iostream>
#include <vector>
#include <queue>
#ifdef MYTHREAD
#include "mythread.hpp"
#else
#include <pthread.h>
#endif
#include "mymutex.hpp"

template<class T,class F> //T任务类型 F任务处理函数 F限定为仿函数 这样函数参数的处理比较方便
class ThreadPool
{

    ThreadPool(int vpn = 5)
#ifdef MYTHREAD
            :_cap(vpn)
            ,startflag(true)
#else
            :_vp(vpn)
            ,_cap(vpn)
            ,startflag(true)
#endif
    {
        pthread_mutex_init(&_m,nullptr);
        pthread_cond_init(&_c,nullptr);
        static_cast<void>(ThreadPool<T,F>::_gc); //防止_gc被优化而被编译器去掉失去内存回收
    }

    ThreadPool(const ThreadPool<T,F>&) = delete;
    ThreadPool<T,F>& operator=(const ThreadPool<T,F>&) = delete;

public:
    static ThreadPool<T,F>* GetCreate(int num = 5) //单例模式
    {
        if(!ThreadPool<T,F>::_tp) //先检查是否已经申请 如果有对象 则直接返回对象指针 避免重复申请损失性能
        {
            lock lk(&ThreadPool<T,F>::_tpm);
            if(!ThreadPool<T,F>::_tp)
            {
                ThreadPool<T,F>::_tp = new ThreadPool<T,F>(num);
            }
        }
        return ThreadPool<T,F>::_tp;
    }

    static void Destroy()
    {
        lock lk(&ThreadPool<T,F>::_tpm);
        if(ThreadPool<T,F>::_tp)
        {
            delete _tp;
            _tp = nullptr;
        }
    }

protected:
    pthread_mutex_t* getmutex() { return &_m; }
    pthread_cond_t* getcond() { return &_c; }

    void ThreadWait() { pthread_cond_wait(getcond(),getmutex()); } //进入等待队列
    void ThreadWakeUp() { pthread_cond_signal(getcond()); } //唤醒一个线程处理任务

    bool taskempty() { return _q.empty(); }
public:
    //执行任务
    static void* threadfunc(void* args)
    {
        ThreadPool<T,F>* tp = static_cast<ThreadPool<T,F>*>(args);
        pthread_detach(pthread_self()); //线程分离 让操作系统自己回收

        while(true)
        {
            T t;
            {
                lock lk(tp->getmutex()); //上锁
                while(tp->taskempty()) tp->ThreadWait(); //如果为空则进入等待队列

                t = tp->pop_task(); //取任务
            }
            //处理任务
            tp->TaskFunc(t);
        }
        return args;
    }
    void TaskFunc(T& task) { func(task); }
public:

    void init() //初始化任务列表
    {
#ifdef MYTHREAD
        if(_vp.size() == 0)
        {
            for(int i = 0;i<_cap;++i)
            _vp.push_back(Thread("thread"+std::to_string(i),threadfunc,this));
        }
#else
#endif
    }


    void start() //创建线程池
    {
        if(startflag)
        {
#ifdef MYTHREAD
            init();
            for(int i = 0;i<_cap;++i)
                _vp[i].run();
#else
            for(int i = 0;i<_cap;++i)
            pthread_create(&_vp[i],nullptr,threadfunc,this);  
#endif
            startflag = false;
        } 
    }

    void check() // 查看线程情况
    {
#ifdef MYTHREAD
        for(int i = 0;i<_cap;++i)
            std::cout<<_vp[i].getname()<<":"<<_vp[i].gettid()<<std::endl;
#else
        for(int i = 0;i<_cap;++i)
            std::cout<<"thread"+std::to_string(i)+":"<<i<<_vp[i]<<std::endl;
#endif

    }

    void push_task(const T& _task)
    {
        lock lk(getmutex()); //排队写入任务
        _q.push(_task); //写入一个任务
        ThreadWakeUp(); //唤醒一个线程
    }

    T pop_task()
    {
        T t = _q.front();
        _q.pop();
        return t;
    }



    ~ThreadPool()
    {
        pthread_mutex_destroy(&_m);
        pthread_cond_destroy(&_c);
    }

    class GC //对象回收
    {
    public:
        ~GC()
        {
            std::cout<<"668"<<std::endl;
            ThreadPool<T,F>::Destroy();
            pthread_mutex_destroy(&_tpm);
        }

    };

private:

#ifdef MYTHREAD
    std::vector<Thread> _vp; //线程池
#else
    std::vector<pthread_t> _vp; //线程池
#endif
    size_t _cap;

    std::queue<T> _q; //任务队列

    pthread_mutex_t _m; //访问互斥锁
    pthread_cond_t _c; //条件变量 - 等待队列
    F func;
    bool startflag; //防止start被重复调用

    static ThreadPool<T,F>* _tp;
    static pthread_mutex_t _tpm;
    static ThreadPool<T,F>::GC _gc;
};

template<class T,class F>
ThreadPool<T,F>* ThreadPool<T,F>::_tp = nullptr;

template<class T,class F>
pthread_mutex_t ThreadPool<T,F>::_tpm = PTHREAD_MUTEX_INITIALIZER;

template<class T,class F>
typename ThreadPool<T,F>::GC ThreadPool<T,F>::_gc;